#ifdef USE_GCLOUD
#include "Tencent/InstallLayerDolphin.h"
#endif

#include "AppDelegate.h"
#include "CCLuaEngine.h"
#include "SimpleAudioEngine.h"
#include "cocos2d.h"
#include "lua_module_register.h"
#include "cocostudio/WidgetReader/WidgetReader.h"
#include "ui/UIHelper.h"
#include "AudioEngine.h"
#include "audio/include/AudioEngine.h"
#include "Localization.h"
#include "network/HttpClient.h"
#include "extend/FileDecoder.h"
#include "extend/RichTextExtend.h"
#include "cocostudio/CocoStudio.h"

// extra lua module
#include "cocos2dx_extra.h"
#include "lua_extensions/lua_extensions_more.h"
#include "luabinding/lua_cocos2dx_extension_filter_auto.hpp"
#include "luabinding/lua_cocos2dx_extension_nanovg_auto.hpp"
#include "luabinding/lua_cocos2dx_extension_nanovg_manual.hpp"
#include "luabinding/cocos2dx_extra_luabinding.h"
#include "luabinding/HelperFunc_luabinding.h"

#include "scripting/lua-bindings/auto/lua_dragonbones_auto.hpp"
#include "scripting/lua-bindings/manual/dragonbones/lua_dragonbones_manual.h"
#include "TcpClientWrapperTolua.hpp"


#include "lua_custom_auto.hpp"
#include "lua_custom_manual.h"

#include "scripting/lua-bindings/auto/lua_battle_auto.hpp"
#include "scripting/lua-bindings/manual/battle/lua_battle_manual.h"

#include "ClearScene.h"
#include "LogoScene.h"
#include "InstallScene.h"

#include "custom/NodePool.hpp"

#ifdef USE_CLOUND_VOICE
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) && (!TARGET_IPHONE_SIMULATOR)
        #define IMAPI_ENABLE 1
    #else
        #define IMAPI_ENABLE 0
    #endif
#else
     #define IMAPI_ENABLE 0
#endif

#if IMAPI_ENABLE > 0
#include "IMAPI.h"
#include "IMAPI-lua.h"
#endif

#ifdef USE_MSDK 
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
#include "Tapm.h"
#include "Tapm_lua.h"
#endif
#include "SafeAPI_lua.h"
#include "GSDKHelper.h"
#include "GemService.h"
#include "lua_gsdk_auto.hpp"
#include "lua_gsdk_manual.hpp"
#endif

#include "TableCache.h"

#include "extend/FileDecoder.h"
#include "DragonBonesHeaders.h"
#include "UserDefaultKeys.h"
#include "EncryptChar.h"
#include "SerializeHelper.hpp"
#include "GeometricRecognizer.h"
#include "2d/CCFontAtlasCache.h"
#include "extend/PolygonCache.hpp"

#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
#include "jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h"
#include "platform/android/jni/JniHelper.h"
#endif

#if (USE_NDK_PROFILE>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "prof.h"
#endif

#include "CCFactory.h"

#ifdef USE_EMACDN
#include "EMA/EmaOverseaSdkApi.hpp"
#include "EMA/PermissionLayer.hpp"
#elif USE_PWRD
#include "Pwrd/PwrdSdkApi.hpp"
#include "Pwrd/PwrdPermissionLayer.hpp"
#endif

int luaopen_protobuf_c(lua_State *L);
//int register_watchbridge(lua_State* L);
void regist_L10N_functions(lua_State* L);

#ifdef USE_IMPROF
extern "C"
{
    int luaopen_lmprof (lua_State *L);
}
#endif

using namespace CocosDenshion;

USING_NS_CC;
using namespace std;
using namespace cocos2d::ui;
using namespace cocos2d::experimental;


static void quick_module_register(lua_State *L)
{

    luaopen_lua_extensions_more(L);
    
    lua_getglobal(L, "_G");
    if (lua_istable(L, -1))//stack:...,_G,
    {
        //register_all_quick_manual(L);
        // extra
        luaopen_cocos2dx_extra_luabinding(L);
        register_all_cocos2dx_extension_filter(L);
        register_all_cocos2dx_extension_nanovg(L);
        register_all_cocos2dx_extension_nanovg_manual(L);
        luaopen_HelperFunc_luabinding(L);
    }
    lua_pop(L, 1);
}

/*
static void addExtendCommands()
{
    //自定义Console命令
    static struct Console::Command commands[] = {
        {"dumplt","dump larged textures",[](int fd, const std::string& args) {
                Director::getInstance()->getScheduler()->performFunctionInCocosThread([fd]{
                    auto textureCache = Director::getInstance()->getTextureCache();
                    std::string info = textureCache->getCachedLargeTextureInfo();
                    info+="\n>";
                    sendBuf(fd,info.c_str(),info.size());
                });}
        },
        {"execstr","executeString",[](int fd, const std::string& args){
            Director::getInstance()->getScheduler()->performFunctionInCocosThread([fd,args]{
                LuaEngine::getInstance()->executeString(args.c_str());
            });
        }}
    };
    
    for (int i = 0; i < sizeof(commands)/sizeof(commands[0]); ++i)
    {
        Director::getInstance()->getConsole()->addCommand(commands[i]);
    }
}
 */

static std::string& replaceAll(std::string& str, const std::string& old_value, const std::string& new_value)
{
    size_t start = 0;
    while (true)
    {
        size_t pos = 0;
        if ((pos = str.find(old_value, start)) != std::string::npos) {
            str.replace(pos, old_value.length(), new_value);
            start = pos + new_value.length();
        }
        else break;
    }
    return str;
}

static Scene * createLogoScene(){
    #if USE_EMACDN && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
    if(!EmaOverseaSdkApi::checkPermissions()){
        return PermissionLayer::createScene();
    }else{
        return LogoScene::createScene(false);
    }
    #elif USE_PWRD && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
    if(!PwrdSdkApi::checkPermissions()){
        return PwrdPermissionLayer::createScene();
    }else{
        return LogoScene::createScene(false);
    }
    #endif
        return LogoScene::createScene(false);
}


EncryptChar* AppDelegate::_encryKey = nullptr;
const char* AppDelegate::_encrySign = "com.lemonade.hope";

AppDelegate::AppDelegate()
{
    
}

AppDelegate::~AppDelegate()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
    NodePool::destroyInstance();
    PolygonCache::destroyInstance();
    dragonBones::CCFactory::releaseInstance();
    cocostudio::destroyCocosStudio();
    AudioEngine::end();
    network::HttpClient::destroyInstance();
#endif

}

//if you want a different context,just modify the value of glContextAttrs
//it will takes effect on all platforms
void AppDelegate::initGLContextAttrs()
{
    //set OpenGL context attributions,now can only set six attributions:
    //red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

static void autoScaleScreen(GLView* glView){
    auto screenSize = glView->getFrameSize();
    float width = screenSize.width;
    
    float height = screenSize.height;
    // if(height<=768 && height>=640 && width<=1280 && width>=960){
    if(height<=768 && height>=640 && width<=1136 && width>=960){
        glView->setDesignResolutionSize(width, height, ResolutionPolicy::FIXED_HEIGHT);
    }else{
        float resScale=width/height;
        if (resScale>1.49&&resScale<1.51) {
            glView->setDesignResolutionSize(960, 640, ResolutionPolicy::NO_BORDER);
        }else if (resScale>1.32&&resScale<1.34){
            glView->setDesignResolutionSize(1024, 768, ResolutionPolicy::NO_BORDER);
        }else if(resScale>1.76&&resScale<1.78){
            glView->setDesignResolutionSize(1136, 640, ResolutionPolicy::NO_BORDER);
        }else if(resScale>1.59&&resScale<1.61){
            glView->setDesignResolutionSize(1228, 768, ResolutionPolicy::NO_BORDER);
        }
        else{
            CCLOG("====>autoScaleScreen unknow screen size w:%.2f h:%.2f",width,height);
            glView->setDesignResolutionSize(1136, 640, ResolutionPolicy::FIXED_HEIGHT);
        }
    }
}


static void pushResPathInLang(std::vector<std::string> & searchPaths, std::string & basePath, std::string & lang)
{
    if (lang != "")
    {
        searchPaths.push_back(basePath + "assets.multilanguage/" + lang + "/");
        searchPaths.push_back(basePath + "assets.multilanguage/" + lang + "/res/");
        searchPaths.push_back(basePath + "assets.multilanguage/" + lang + "/res/ui2/");
        searchPaths.push_back(basePath + "assets.multilanguage/" + lang + "/res/map/");
        searchPaths.push_back(basePath + "assets.multilanguage/" + lang + "/src/");
    }
}

static void pushResPath(std::vector<std::string> & searchPaths, std::string & basePath)
{
    searchPaths.push_back(basePath + "");
    searchPaths.push_back(basePath + "res/");
    searchPaths.push_back(basePath + "res/ui2/");
    searchPaths.push_back(basePath + "res/map/");
    searchPaths.push_back(basePath + "src/");
}


void AppDelegate::setSearchPaths()
{
    std::string lang = Localization::getInstance()->getUserSelectLang();
    
    std::string documentPath = AppDelegate::getStorePath() + "/";
    std::vector<std::string> searchPaths;
    
    
    std::string hotBasePath = documentPath + "assets/";
    std::string rootPath = "";

    pushResPathInLang(searchPaths, hotBasePath, lang);
    pushResPathInLang(searchPaths, rootPath, lang);
    
    pushResPath(searchPaths, hotBasePath);
    pushResPath(searchPaths, documentPath);
    searchPaths.push_back(FileUtils::getInstance()->getWritablePath());
    pushResPath(searchPaths, rootPath);
    
//    searchPaths.push_back("assets/");

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
    std::string appPath = Application::getInstance()->getAppPath();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
    appPath.append("/../../");
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
    appPath.append("/../../../");
#endif
    appPath = replaceAll(appPath, "\\", "/");

    // add project's root directory to search path
    searchPaths.insert(searchPaths.begin(), appPath + "src/");
    searchPaths.insert(searchPaths.begin(), appPath + "res/");
    searchPaths.insert(searchPaths.begin(), appPath + "res/ui/");
    searchPaths.insert(searchPaths.begin(), appPath + "res/ui2/");
    searchPaths.insert(searchPaths.begin(), appPath + "res/map/");
    searchPaths.insert(searchPaths.begin(), appPath + "editor/");
    searchPaths.insert(searchPaths.begin(), appPath);
    
    
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/src/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/res/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/res/ui/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/res/ui2/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/res/map/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/dev/res/");
    searchPaths.insert(searchPaths.begin(), appPath + "assets.multilanguage/" + lang + "/dev/res/ui2/");
    
    searchPaths.insert(searchPaths.begin(), appPath + "src.multilanguage/" + lang + "/src/");

#endif

    FileUtils::getInstance()->setSearchPaths(searchPaths);
}

void AppDelegate::loadL10NStr(bool async)
{
    std::string jsonPath = FileUtils::getInstance()->fullPathForFilename("res/data/string.json");
    cocos2d::log("====>load string json from %s",jsonPath.c_str());
    
    Data data = FileUtils::getInstance()->getDataFromFile(jsonPath);
    unsigned long size = data.getSize();
    unsigned char* buf = data.getBytes();
    
    Data outData;
    if(FileDecoder::decode(data,outData))
    {
        size = outData.getSize();
        buf = outData.getBytes();
    }
    std::string content((char *)buf, size);
    Localization::getInstance()->initWithJson(content);
    
//    if(async){
//        FileUtils::getInstance()->getStringFromFile(jsonPath,[](std::string content){
//            Localization::getInstance()->initWithJson(content);
//        });
//    }
//    else{
//        Localization::getInstance()->initWithJson(FileUtils::getInstance()->getStringFromFile(jsonPath));
//    }
}




void AppDelegate::relaunchApp(bool withLog)
{
    SpriteFrameCache::getInstance()->releaseSpriteFramesFromFile("ui2/ui_resources/common.plist");
    Director::getInstance()->clearCache();
    AppDelegate::initGameConfig();

    Scene* scene = nullptr;
    if(withLog){
        scene = createLogoScene();
    }else{
        scene=TransitionFade::create(1.0f, createInstallScene(),Color3B::BLACK);
    }
    Director::getInstance()->replaceScene(scene);
}

static int tolua_Native_Function_relaunchApp(lua_State* tolua_S)
{
    int argc = lua_gettop(tolua_S);
    bool withLog = true;
    if(argc>0){
        withLog = tolua_toboolean(tolua_S,1,0);
    }
    AppDelegate::relaunchApp(withLog);
    return 0;
}

static int tolua_Native_Function_restartApp(lua_State* tolua_S)
{
    AppDelegate::restartApp();
    return 0;
}

static int tolua_Native_Function_closeApp(lua_State* tolua_S)
{
    AppDelegate::closeApp();
    return 0;
}

static int tolua_Native_Function_getStorePath(lua_State* tolua_S)
{
    std::string path = AppDelegate::getStorePath();
    tolua_pushstring(tolua_S, path.c_str());
    return 1;
}

static int tolua_Native_Function_getPackageName(lua_State* tolua_S)
{
    std::string path = Application::getInstance()->getPackageName();
    tolua_pushstring(tolua_S, path.c_str());
    return 1;
}

static int tolua_Native_Function_getPhoneName(lua_State* tolua_S)
{
    std::string name = Application::getInstance()->getPhoneName();
    tolua_pushstring(tolua_S, name.c_str());
    return 1;
}

static int tolua_Native_Function_SetTimeoutForHttpConnect(lua_State* tolua_S)
{
    network::HttpClient::getInstance()->setTimeoutForConnect(tolua_tonumber(tolua_S,1,0));
    return 0;
}

static int tolua_Native_Function_SetTimeoutForHttpRead(lua_State* tolua_S)
{
    network::HttpClient::getInstance()->setTimeoutForRead(tolua_tonumber(tolua_S,1,0));
    return 0;
}

static int tolua_Native_Function_PrintLeaks(lua_State* tolua_S)
{
#if CC_REF_LEAK_DETECTION
    Ref::printLeaks();
#endif
    return 0;
}

static int tolua_Native_Function_EnableLeakMonitor(lua_State* tolua_S)
{
#if CC_REF_LEAK_DETECTION
    Ref::enableLeakMonitor(tolua_toboolean(tolua_S, 1, 0));
#endif
    return 0;
}

static int tolua_Native_Function_GetAppVersion(lua_State* tolua_S)
{
    std::string version = Application::getInstance()->getAppVersion();
    tolua_pushstring(tolua_S, version.c_str());
    return 1;
}

static int tolua_Native_Function_GetResVersion(lua_State* tolua_S)
{
    std::string version = Application::getInstance()->getResourceVersion();
    tolua_pushstring(tolua_S, version.c_str());
    return 1;
}

static int tolua_Native_Function_getExternalPath(lua_State* tolua_S)
{
    std::string v = AppDelegate::getExternalPath();
    tolua_pushstring(tolua_S, v.c_str());
    return 1;
}

static int tolua_Native_Function_profileStart(lua_State* tolua_S)
{
#if (USE_NDK_PROFILE>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    setenv("CPUPROFILE_FREQUENCY", "500", 1); /* Change to 500 interrupts per second */
    monstartup("libgame.so");
#endif
    return 0;
}

static int tolua_Native_Function_profileEnd(lua_State* tolua_S)
{
#if (USE_NDK_PROFILE>0 && CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    moncleanup();
#endif
    return 0;
}

static int tolua_Native_Function_checkPermissions(lua_State* tolua_S)
{
    int args = lua_gettop(tolua_S);
    if(args == 1){
        std::string permissions = lua_tostring(tolua_S, 1);
        lua_pop(tolua_S, 1);
        bool isTrue = AppDelegate::checkPermissions(permissions.c_str());
        lua_pushboolean(tolua_S, isTrue);
        return 1;
    }
    return 0;
}

static int tolua_Native_Function_requestPermissions(lua_State* tolua_S)
{
    int args = lua_gettop(tolua_S);
    if(args == 1){
        std::string permissions = lua_tostring(tolua_S, 1);
        AppDelegate::requestPermissions(permissions.c_str());
    }
    return 0;
}

static int tolua_Native_Function_goAppSetting(lua_State* tolua_S)
{
    AppDelegate::goAppSetting();
    return 0;
}


static int tolua_Native_Function_SetClippingEnabled(lua_State* tolua_S)
{
    bool enable = tolua_toboolean(tolua_S, 1, 0);
    Director::getInstance()->setClippingEnabled(enable);
    return 0;
}

DollarRecognizer::GeometricRecognizer* s_recognizer = nullptr;
static int tolua_Native_Function_DollarRecognizer(lua_State* L)
{
    if(!s_recognizer){
        s_recognizer = new DollarRecognizer::GeometricRecognizer();
        s_recognizer->loadTemplates();
    }
    

    if (!tolua_istable(L, 1, 0, nullptr) )
    {
        return 0;
    }
    
    size_t len = lua_objlen(L, 1);
    if (len > 0)
    {
        DollarRecognizer::Path2D path2d;
        for (size_t i = 0; i < len; ++i)
        {
            DollarRecognizer::Point2D p;
            lua_pushnumber(L,i + 1);
            lua_gettable(L,1);
            
            lua_pushstring(L, "x");
            lua_gettable(L, 2);
            p.x = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
            lua_pop(L, 1);
            
            lua_pushstring(L, "y");
            lua_gettable(L, 2);
            p.y = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
            lua_pop(L, 1);
            
            lua_pop(L, 1);
            path2d.push_back(p);
        }
        std::reverse(path2d.begin(), path2d.end());
        DollarRecognizer::RecognitionResult res = s_recognizer->recognize(path2d);
        lua_pushstring(L,res.name.c_str());
        lua_pushnumber(L,res.score);
        return 2;
    }
    
    return 0;
}

static int tolua_Native_Function_DumpFontAtlasImages(lua_State* L)
{
    FontAtlasCache::dumpImages();
    return 0;
}

static int tolua_Native_Function_LaunchClearScene(lua_State* L)
{
    AppDelegate::launchClearScene();
    return 0;
}

static int tolua_Native_Function_getAppPath(lua_State* L)
{
    lua_pushstring(L, Application::getInstance()->getAppPath().c_str());
    return 1;
}

static int tolua_Native_Function_startGrayUpdate(lua_State* L)
{
#ifdef USE_GCLOUD
    auto scene = Director::getInstance()->getRunningScene();
    InstallLayerDolphin* hotFixScene = dynamic_cast<InstallLayerDolphin*>(scene->getChildByName("HotFixScene"));
    if (hotFixScene != nullptr)
    {
        int argc = lua_gettop(L);
        if (argc == 2)
        {
            const char* openid = tolua_tostring(L,1,0);
            const char* zoneid = tolua_tostring(L,2,0);
            hotFixScene->startGrayUpdate(openid, zoneid);
            return 0;
        }
    }
#endif
    EventCustom grayUpdateEvent("GRAY_UPDATE_COMPLETE");
    std::string retStr = "comp";
    grayUpdateEvent.setUserStr(retStr);
    Director::getInstance()->getEventDispatcher()->dispatchEvent(&grayUpdateEvent);
    return 0;
}

static void extendNativeFunctions(lua_State* tolua_S)
{
    tolua_open(tolua_S);
    tolua_module(tolua_S,"cc",0);
    tolua_beginmodule(tolua_S,"cc");
    tolua_function(tolua_S,"RelaunchApp",tolua_Native_Function_relaunchApp);
    tolua_function(tolua_S,"RestartApp",tolua_Native_Function_restartApp);
    tolua_function(tolua_S,"CloseApp",tolua_Native_Function_closeApp);
    tolua_function(tolua_S,"GetStorePath",tolua_Native_Function_getStorePath);
    tolua_function(tolua_S,"GetPackageName",tolua_Native_Function_getPackageName);
    tolua_function(tolua_S,"GetPhoneName",tolua_Native_Function_getPhoneName);
    tolua_function(tolua_S,"SetTimeoutForHttpConnect",tolua_Native_Function_SetTimeoutForHttpConnect);
    tolua_function(tolua_S,"SetTimeoutForHttpRead",tolua_Native_Function_SetTimeoutForHttpRead);
    tolua_function(tolua_S,"PrintLeaks",tolua_Native_Function_PrintLeaks);
    tolua_function(tolua_S,"EnableLeakMonitor",tolua_Native_Function_EnableLeakMonitor);
    tolua_function(tolua_S,"GetAppVersion",tolua_Native_Function_GetAppVersion);
    tolua_function(tolua_S,"GetResVersion",tolua_Native_Function_GetResVersion);
    tolua_function(tolua_S,"getExternalPath",tolua_Native_Function_getExternalPath);
    tolua_function(tolua_S,"ProfileStart",tolua_Native_Function_profileStart);
    tolua_function(tolua_S,"ProfileEnd",tolua_Native_Function_profileEnd);
    tolua_function(tolua_S,"SetClippingEnabled",tolua_Native_Function_SetClippingEnabled);
    tolua_function(tolua_S,"DollarRecognizer",tolua_Native_Function_DollarRecognizer);
    tolua_function(tolua_S,"DumpFontAtlasImages",tolua_Native_Function_DumpFontAtlasImages);
    tolua_function(tolua_S,"LaunchClearScene",tolua_Native_Function_LaunchClearScene);
    tolua_function(tolua_S,"getAppPath",tolua_Native_Function_getAppPath);
    tolua_function(tolua_S,"startGrayUpdate",tolua_Native_Function_startGrayUpdate);
    tolua_function(tolua_S,"checkPermissions",tolua_Native_Function_checkPermissions);
    tolua_function(tolua_S,"requestPermissions",tolua_Native_Function_requestPermissions);
    tolua_function(tolua_S,"goAppSetting",tolua_Native_Function_goAppSetting);
    tolua_endmodule(tolua_S);
}

const std::string& AppDelegate::getStorePath()
{
    static std::string path = FileUtils::getInstance()->getWritablePath()+Application::getInstance()->getPackageName();
    return path;
}

std::string AppDelegate::getAppVersion()
{
    // Application version's format is "x.x.x".
    return this->getVersion();
}

std::string AppDelegate::getRemoteAppVersion()
{
#ifdef USE_EMACDN
    return EmaOverseaSdkApi::getVersionNum();
#elif USE_PWRD
    return PwrdSdkApi::getRemoteAppVersion();
#else
    return "";
#endif
}

std::string AppDelegate::getResourceVersion()
{
    // Resource version's format is "x".
    std::string ret;
    auto userDefault = UserDefault::getInstance();
    ret = userDefault->getStringForKey(UD_RES_VERSION);
    if(ret.empty()){
        ret = Configuration::getInstance()->getValue(UD_RES_VERSION).asString();
    }

    return ret;
}

std::string AppDelegate::getRemoteResourceVersion()
{
    std::string ret = "0";
#ifdef USE_EMACDN
    ret = EmaOverseaSdkApi::getResourceVersion();
#elif USE_PWRD
    ret = PwrdSdkApi::getRemoteResourceVersion();
#else
    
#endif
    return ret;
}

void AppDelegate::setAppVersion(const std::string& s)
{
    auto userDefault = UserDefault::getInstance();
    userDefault->setStringForKey(UD_APP_VERSION, s);
    userDefault->flush();
}

void AppDelegate::setResourceVersion(const std::string& s)
{
    auto userDefault = UserDefault::getInstance();
    userDefault->setStringForKey(UD_RES_VERSION, s);
    userDefault->flush();
    Configuration::getInstance()->setValue(UD_RES_VERSION, Value(s));
}

static  std::string _externalPath = "";
const std::string& AppDelegate::getExternalPath()
{
    if(_externalPath.empty()){
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
        _externalPath=getExternalPathJNI();
#endif
    }
    return _externalPath;
}


bool AppDelegate::checkPermissions(const char * permissions){
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
    return checkPermissionsJNI(permissions);
#else
    return false;
#endif
}
// 监听
void AppDelegate::requestPermissions(const char * permissions){
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
    requestPermissionsJNI(permissions);
#endif
}
void AppDelegate::goAppSetting(){
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
    goAppSettingJNI();
#endif
}


void AppDelegate::removeAllCache()
{
    CSLoader::getInstance()->purge();
    
    //TODO
    //dragonBones::DBCCFactory::getInstance()->dispose(true);
    
    Director::getInstance()->purgeCachedData();
}

void AppDelegate::initGameConfig()
{
    std::string storePath = AppDelegate::getStorePath()+"/";
    if(!FileUtils::getInstance()->isDirectoryExist(storePath))
    {
        FileUtils::getInstance()->createDirectory(storePath);
    }
    
    Configuration* configuration = Configuration::getInstance();
    AppDelegate::setSearchPaths();
    if(FileUtils::getInstance()->isFileExist("config.plist"))
    {
        configuration->loadConfigFile("config.plist");
    }
    if(FileUtils::getInstance()->isFileExist("config_user.plist"))
    {
        configuration->loadConfigFile("config_user.plist");
    }
    AppDelegate::setSearchPaths();
    
    cocos2d::log("===>AppDelegate getWritablePath %s ", FileUtils::getInstance()->getWritablePath().c_str());
    cocos2d::log("===>AppDelegate getStorePath %s ", storePath.c_str());
    cocos2d::log("===>AppDelegate getExternalPath %s ", AppDelegate::getExternalPath().c_str());

    AppDelegate::loadL10NStr(true);
    cocos2d::ui::Helper::setDefaultTTFFile(configuration->getValue("DefaultFont", Value("ui2/fonts/ArialUnicodeMS.ttf")).asString());
}


bool AppDelegate::applicationDidFinishLaunching()
{
    
// #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
//     Splus::Agent::initWithAppIdAndChannelId("s4119a67b4686cd0b5663a370431fe6f9", "test",true);
// #endif

    cocos2d::Device::setKeepScreenOn(true);
    
    _encryKey = new EncryptChar("dndk``mhbgf");
    
    FileDecoder::setXXTEAKeyAndSign(_encryKey->decrypt(), _encryKey->getLen(), _encrySign, (int)strlen(_encrySign));
    
    AppDelegate::initGameConfig();

     // initialize director
    Configuration* configuration = Configuration::getInstance();
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        float width = configuration->getValue("ScreenWidth",Value(1136.0f)).asFloat();
        float height = configuration->getValue("ScreenHeight",Value(640.0f)).asFloat();
        cocos2d::Size viewSize(width,height);
        string title = "client";
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
        extern void createSimulator(const char* viewName, float width, float height, bool isLandscape = true, float frameZoomFactor = 1.0f);
        bool isLanscape = true;
        createSimulator(title.c_str(), viewSize.width, viewSize.height, isLanscape);
        glview = director->getOpenGLView();
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
        glview = GLViewImpl::createWithRect(title, cocos2d::Rect(0, 0, width, height));
        director->setOpenGLView(glview);
#else
        glview = cocos2d::GLViewImpl::createWithRect(title.c_str(), cocos2d::Rect(0, 0, viewSize.width, viewSize.height));
        director->setOpenGLView(glview);
#endif 
    }
    
    autoScaleScreen(glview);

    director->setProjection(Director::Projection::_2D);

    FileUtils::getInstance()->setPopupNotify(false);
    
    auto scene=createLogoScene();
    
    // run
    director->runWithScene(scene);
    
    return true;
}

void AppDelegate::delayInit()
{
    if(_encryKey)
    {
//        addExtendCommands();

        // Check whether appication is reinstalled.
        // If it is, then the hotfix folder must be removed.
        auto userDefault = UserDefault::getInstance();
        string appVersion = Application::getInstance()->getAppVersion();
        string oldAppVersion = userDefault->getStringForKey(UD_APP_VERSION);
        cocos2d::log("====>appVersion:%s oldAppVersion:%s", appVersion.c_str(), oldAppVersion.c_str());
        if(appVersion != oldAppVersion)
        {
            AppDelegate::setAppVersion(appVersion);
            
#ifdef USE_GCLOUD
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
            //ios reinstall apk need extract pack
            userDefault->setIntegerForKey(UD_FIRST_EXTRACT,-1);
            userDefault->flush();
            cocos2d::log("GCLOUD ios - update UD_FIRST_EXTRACT -1");
#endif
#else
            std::string documentPath = getStorePath()+"/";
            std::string hotBasePath = documentPath + "assets/";
            FileUtils::getInstance()->removeDirectory(hotBasePath);
            cocos2d::log("Hotfix - Cleanup base folder %s ", hotBasePath.c_str());
#endif
            
        }

//        AppDelegate::loadL10NStr(true);

        auto engine = LuaEngine::getInstance();
        ScriptEngineManager::getInstance()->setScriptEngine(engine);

        LuaStack* stack = engine->getLuaStack();
        stack->setXXTEAKeyAndSign(_encryKey->decrypt(), _encryKey->getLen(), _encrySign, (int)strlen(_encrySign));

        lua_State* L = engine->getLuaStack()->getLuaState();

        lua_module_register(L);

        regist_L10N_functions(L);

        extendNativeFunctions(L);
        
        //quick
        quick_module_register(L);
        
        TableCache::register2lua(L);
        
        // im
#if IMAPI_ENABLE > 0
// #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        register_all_imapi(L);
#endif
    
    	//battle
    	register_all_battle(L);
        register_battle_manual(L);
        
        //register custom function
        register_all_custom(L);
        register_all_custom_manual(L);
        
        //register_watchbridge(L);

#ifdef USE_MSDK 
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID

        //register tapm
        TApm::setAppId("APM_WJDYZ");
        // TApm::setUserId("userid");//可选，openid为用户标识id，如果对于单个用 户的性能状态感兴趣，请设置openid
#if COCOS2D_DEBUG >= 1
        TApm::enableDebugMode();//调试情况下打开日志，可选 
#endif
        TApm::initApmCtx();
        register_all_tapm(L);

        //register gsdk

#endif
        //register safe api
        register_all_safeapi(L);
        
        std::string appId = Configuration::getInstance()->getValue("GSDK_APPID",Value("1105873472")).asString();
        int env = Configuration::getInstance()->getValue("GSDK_ENV",Value(1)).asInt();
        cocos2d::log("GSDK init appId=%s, env=%d ", appId.c_str(), env);
        
#if COCOS2D_DEBUG >= 1
        GemService::InitWithBeacon(appId.c_str(), true, env);
#else
        GemService::InitWithBeacon(appId.c_str(), false, env);
#endif
       
        register_all_gsdk(L);
        register_all_gsdk_manual(L);
#endif

        //DragonBones
        register_all_dragonbones(L);
        register_dragonbones_manual(L);
        
        //PBC
        luaopen_protobuf_c(L);
        
        register_tcpclientwrapper_module(L);
        
        SerializeHelper::register2lua(L);
#ifdef USE_IMPROF
        luaopen_lmprof(L);
#endif
        
        RichTextExtend::extend();
   

        Helper::setGlobalTouchEvent([stack](cocos2d::ui::Widget* widget, int event){
            lua_State* lua_state = stack->getLuaState();
            if(!lua_state) return ;
            lua_getglobal(lua_state, "globalTouchEventHandler");       /* query function by name, stack: function */
            if (!lua_isfunction(lua_state, -1))
            {
                lua_pop(lua_state, 1);
                return ;
            }
            
            stack->pushObject(widget, "cc.Widget");
            stack->pushInt(event);
            stack->executeFunction(2);
        });
        
        Helper::setFrameEventHandler([stack](const std::string& eventName){
            lua_State* lua_state = stack->getLuaState();
            if(!lua_state) return ;
            lua_getglobal(lua_state, "globalFrameEventHandler");       /* query function by name, stack: function */
            if (!lua_isfunction(lua_state, -1))
            {
                lua_pop(lua_state, 1);
                return ;
            }
            
            stack->pushString(eventName.c_str());
            stack->executeFunction(1);
        });
        
        cocos2d::ui::Helper::setGetLStringDelegate([](const std::string& key)->std::string{
            std::string mark = "@string/";
            auto index = key.find(mark,0);
            if(index == std::string::npos)
            {
                return key;
            }
            
            std::string subKey = key.substr(mark.length(),key.length());
            return Localization::getInstance()->getStr(subKey);
        });
        
       

        delete _encryKey;
        _encryKey = nullptr;
    }
}

void AppDelegate::gsdkSetEvent(int tag, bool state, const char* msg,  bool authorize, bool finish)
{
#ifdef USE_MSDK
    GemService::SetEvent(tag, state, msg, authorize, finish);
#endif
}

bool AppDelegate::isGameLogin()
{
    auto engine = LuaEngine::getInstance();
    LuaStack* stack = engine->getLuaStack();

    lua_State* lua_state = stack->getLuaState();
    if(!lua_state) return false;
    lua_getglobal(lua_state, "globalIsGameLogin");       /* query function by name, stack: function */
    if (!lua_isfunction(lua_state, -1))
    {
        lua_pop(lua_state, 1);
        return false;
    }

    lua_pcall(lua_state,0,1,0);
    bool isLogin = tolua_toboolean(lua_state, -1, false);
    return isLogin;
}

void AppDelegate::restartApp()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    Director::getInstance()->end();
    const char* jniClass = "org/cocos2dx/lib/Cocos2dxActivity";
    JniHelper::callStaticVoidMethod(jniClass, "restartApp");
#endif
}

void AppDelegate::closeApp()
{
    Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

void AppDelegate::launchClearScene()
{
    auto scene = ClearScene::createScene();
    Director::getInstance()->replaceScene(scene);
}

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground()
{
    Director::getInstance()->stopAnimation();

    //SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
    
    AudioEngine::pauseAll();
    
#if IMAPI_ENABLE > 0
// #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    imapi::IMAPI::getInstance()->Pause();
#endif
    
    Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("APP_ENTER_BACKGROUND_EVENT");
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
    Director::getInstance()->startAnimation();

    //SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
    
    AudioEngine::resumeAll();
    
#if IMAPI_ENABLE > 0
// #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    imapi::IMAPI::getInstance()->Resume();
#endif
    
    Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("APP_ENTER_FOREGROUND_EVENT");
}

void AppDelegate::applicationDidReceiveMemoryWarning()
{
    /*
     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
     */
    cocos2d::Director::getInstance()->purgeCachedData();
    
    Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("APP_MEMORY_WARNING_EVENT");
}
